#include "wx/wxprec.h"
#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT

#include "wx/memory.h"

#if wxUSE_THREADS
#include "wx/thread.h"
#endif

#include <stdlib.h>

#include "wx/ioswrap.h"

#if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
&& !defined( __MWERKS__ ) && !defined(__SALFORDC__)
#include <memory.h>
#endif

#include <stdarg.h>
#include <string.h>

#if wxUSE_THREADS && defined(__WXDEBUG__)
#define USE_THREADSAFE_MEMORY_ALLOCATION 1
#else
#define USE_THREADSAFE_MEMORY_ALLOCATION 0
#endif


#ifdef new
#undef new
#endif

#define MemStartCheck  0x23A8
#define MemMidCheck  0xA328
#define MemEndCheck 0x8A32
#define MemFillChar 0xAF
#define MemStructId  0x666D

void wxMemStruct::ErrorMsg( const char * mesg ) {
  wxLogMessage( wxT( "wxWidgets memory checking error: %s" ), mesg );
  PrintNode();
}

void wxMemStruct::ErrorMsg() {
  wxLogMessage( wxT( "wxWidgets over/underwrite memory error:" ) );
  PrintNode();
}

int wxMemStruct::AssertList() {
  if( wxDebugContext::GetHead() != 0 && !( wxDebugContext::GetHead() )->AssertIt() ||
      wxDebugContext::GetTail() != 0 && ! wxDebugContext::GetTail()->AssertIt() ) {
    ErrorMsg( "Head or tail pointers trashed" );
    return 0;
  }
  return 1;
}

int wxMemStruct::AssertIt() {
  return ( m_id == MemStructId &&
           ( m_prev == 0 || m_prev->m_id == MemStructId ) &&
           ( m_next == 0 || m_next->m_id == MemStructId ) );
}

int wxMemStruct::Append() {
  if( ! AssertList() ) {
    return 0;
  }
  if( wxDebugContext::GetHead() == 0 ) {
    if( wxDebugContext::GetTail() != 0 ) {
      ErrorMsg( "Null list should have a null tail pointer" );
      return 0;
    }
    ( void ) wxDebugContext::SetHead( this );
    ( void ) wxDebugContext::SetTail( this );
  } else {
    wxDebugContext::GetTail()->m_next = this;
    this->m_prev = wxDebugContext::GetTail();
    ( void ) wxDebugContext::SetTail( this );
  }
  return 1;
}

int wxMemStruct::Unlink() {
  if( ! AssertList() ) {
    return 0;
  }
  if( wxDebugContext::GetHead() == 0 || wxDebugContext::GetTail() == 0 ) {
    ErrorMsg( "Trying to remove node from empty list" );
    return 0;
  }
  if( m_prev == 0 ) {
    if( this != wxDebugContext::GetHead() ) {
      ErrorMsg( "No previous node for non-head node" );
      return 0;
    }
    ( void ) wxDebugContext::SetHead( m_next );
  } else {
    if( ! m_prev->AssertIt() ) {
      ErrorMsg( "Trashed previous pointer" );
      return 0;
    }
    if( m_prev->m_next != this ) {
      ErrorMsg( "List is inconsistent" );
      return 0;
    }
    m_prev->m_next = m_next;
  }
  if( m_next == 0 ) {
    if( this != wxDebugContext::GetTail() ) {
      ErrorMsg( "No next node for non-tail node" );
      return 0;
    }
    ( void ) wxDebugContext::SetTail( m_prev );
  } else {
    if( ! m_next->AssertIt() ) {
      ErrorMsg( "Trashed next pointer" );
      return 0;
    }
    if( m_next->m_prev != this ) {
      ErrorMsg( "List is inconsistent" );
      return 0;
    }
    m_next->m_prev = m_prev;
  }
  return 1;
}

int wxMemStruct::CheckBlock() {
  int nFailures = 0;
  if( m_firstMarker != MemStartCheck ) {
    nFailures++;
    ErrorMsg();
  }
  char * pointer = wxDebugContext::MidMarkerPos( ( char * ) this );
  if( * ( wxMarkerType * ) pointer != MemMidCheck ) {
    nFailures++;
    ErrorMsg();
  }
  pointer = wxDebugContext::EndMarkerPos( ( char * ) this, RequestSize() );
  if( * ( wxMarkerType * ) pointer != MemEndCheck ) {
    nFailures++;
    ErrorMsg();
  }
  return nFailures;
}

int wxMemStruct::CheckAllPrevious() {
  int nFailures = 0;
  for( wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev ) {
    if( st->AssertIt() ) {
      nFailures += st->CheckBlock();
    } else
    { return -1; }
  }
  return nFailures;
}

void wxMemStruct::SetDeleted() {
  m_id = MemFillChar;
}

int wxMemStruct::IsDeleted() {
  return ( m_id == MemFillChar );
}

void wxMemStruct::PrintNode() {
  if( m_isObject ) {
    wxObject *obj = ( wxObject * )m_actualData;
    wxClassInfo *info = obj->GetClassInfo();
    wxString msg;
    if( m_fileName ) {
      msg.Printf( wxT( "%s(%d): " ), m_fileName, ( int )m_lineNum );
    }
    if( info && info->GetClassName() ) {
      msg += info->GetClassName();
    } else
    { msg += wxT( "object" ); }
    wxString msg2;
    msg2.Printf( wxT( " at 0x%lX, size %d" ), ( long )GetActualData(), ( int )RequestSize() );
    msg += msg2;
    wxLogMessage( msg );
  } else {
    wxString msg;
    if( m_fileName ) {
      msg.Printf( wxT( "%s(%d): " ), m_fileName, ( int )m_lineNum );
    }
    msg += wxT( "non-object data" );
    wxString msg2;
    msg2.Printf( wxT( " at 0x%lX, size %d\n" ), ( long )GetActualData(), ( int )RequestSize() );
    msg += msg2;
    wxLogMessage( msg );
  }
}

void wxMemStruct::Dump() {
  if( !ValidateNode() ) {
    return;
  }
  if( m_isObject ) {
    wxObject *obj = ( wxObject * )m_actualData;
    wxString msg;
    if( m_fileName ) {
      msg.Printf( wxT( "%s(%d): " ), m_fileName, ( int )m_lineNum );
    }
    if( obj->GetClassInfo() && obj->GetClassInfo()->GetClassName() ) {
      msg += obj->GetClassInfo()->GetClassName();
    } else
    { msg += wxT( "unknown object class" ); }
    wxString msg2;
    msg2.Printf( wxT( " at 0x%lX, size %d" ), ( long )GetActualData(), ( int )RequestSize() );
    msg += msg2;
    wxDebugContext::OutputDumpLine( msg );
  } else {
    wxString msg;
    if( m_fileName ) {
      msg.Printf( wxT( "%s(%d): " ), m_fileName, ( int )m_lineNum );
    }
    wxString msg2;
    msg2.Printf( wxT( "non-object data at 0x%lX, size %d" ), ( long )GetActualData(), ( int )RequestSize() );
    msg += msg2;
    wxDebugContext::OutputDumpLine( msg );
  }
}

int wxMemStruct::ValidateNode() {
  char * startPointer = ( char * ) this;
  if( !AssertIt() ) {
    if( IsDeleted() ) {
      ErrorMsg( "Object already deleted" );
    }
    return 0;
  }
  if( Marker() != MemStartCheck ) {
    ErrorMsg();
  }
  if( * ( wxMarkerType * ) wxDebugContext::MidMarkerPos( startPointer ) != MemMidCheck ) {
    ErrorMsg();
  }
  if( * ( wxMarkerType * ) wxDebugContext::EndMarkerPos( startPointer,
      RequestSize() ) !=
      MemEndCheck ) {
    ErrorMsg();
  }
  if( Marker() != MemStartCheck ||
      * ( wxMarkerType * ) wxDebugContext::MidMarkerPos( startPointer )
      != MemMidCheck ||
      * ( wxMarkerType * ) wxDebugContext::EndMarkerPos( startPointer,
          RequestSize() ) != MemEndCheck ) {
    ErrorMsg();
    return 0;
  }
  return 1;
}

wxMemStruct *wxDebugContext::m_head = NULL;
wxMemStruct *wxDebugContext::m_tail = NULL;

bool wxDebugContext::m_checkPrevious = false;
int wxDebugContext::debugLevel = 1;
bool wxDebugContext::debugOn = true;
wxMemStruct *wxDebugContext::checkPoint = NULL;

static wxMarkerType markerCalc[2];
int wxDebugContext::m_balign = ( int )( ( char * )&markerCalc[1] - ( char* )&markerCalc[0] );
int wxDebugContext::m_balignmask = ( int )( ( char * )&markerCalc[1] - ( char* )&markerCalc[0] ) - 1;

wxDebugContext::wxDebugContext( void ) {
}

wxDebugContext::~wxDebugContext( void ) {
}

size_t wxDebugContext::CalcAlignment() {
  wxMarkerType ar[2];
  return ( char * ) &ar[1] - ( char * ) &ar[0];
}


char * wxDebugContext::StructPos( const char * buf ) {
  return ( char * ) buf;
}

char * wxDebugContext::MidMarkerPos( const char * buf ) {
  return StructPos( buf ) + PaddedSize( sizeof( wxMemStruct ) );
}

char * wxDebugContext::CallerMemPos( const char * buf ) {
  return MidMarkerPos( buf ) + PaddedSize( sizeof( wxMarkerType ) );
}

char * wxDebugContext::EndMarkerPos( const char * buf, const size_t size ) {
  return CallerMemPos( buf ) + PaddedSize( size );
}

char * wxDebugContext::StartPos( const char * caller ) {
  return ( ( char * )( caller - wxDebugContext::PaddedSize( sizeof( wxMarkerType ) ) -
                       wxDebugContext::PaddedSize( sizeof( wxMemStruct ) ) ) );
}

size_t wxDebugContext::GetPadding( const size_t size ) {
  size_t pad = size % CalcAlignment();
  return ( pad ) ? sizeof( wxMarkerType ) - pad : 0;
}

size_t wxDebugContext::PaddedSize( const size_t size ) {
  int padb;
  padb = size & m_balignmask;
  if( padb ) {
    return( size + m_balign - padb );
  } else
  { return( size ); }
}

size_t wxDebugContext::TotSize( const size_t reqSize ) {
  return ( PaddedSize( sizeof( wxMemStruct ) ) + PaddedSize( reqSize ) +
           2 * sizeof( wxMarkerType ) );
}

void wxDebugContext::TraverseList( PmSFV func, wxMemStruct *from ) {
  if( !from ) {
    from = wxDebugContext::GetHead();
  }
  wxMemStruct * st = NULL;
  for( st = from; st != 0; st = st->m_next ) {
    void* data = st->GetActualData();
    if( data != ( void* ) wxLog::GetActiveTarget() ) {
      ( st->*func )();
    }
  }
}

bool wxDebugContext::PrintList( void ) {
  #ifdef __WXDEBUG__
  TraverseList( ( PmSFV )&wxMemStruct::PrintNode, ( checkPoint ? checkPoint->m_next : ( wxMemStruct* )NULL ) );
  return true;
  #else
  return false;
  #endif
}

bool wxDebugContext::Dump( void ) {
  #ifdef __WXDEBUG__
  {
    wxChar* appName = ( wxChar* ) wxT( "application" );
    wxString appNameStr;
    if( wxTheApp ) {
      appNameStr = wxTheApp->GetAppName();
      appName = WXSTRINGCAST appNameStr;
      OutputDumpLine( wxT( "----- Memory dump of %s at %s -----" ), appName, WXSTRINGCAST wxNow() );
    } else
    { OutputDumpLine( wxT( "----- Memory dump -----" ) ); }
  }
  TraverseList( ( PmSFV )&wxMemStruct::Dump, ( checkPoint ? checkPoint->m_next : ( wxMemStruct* )NULL ) );
  OutputDumpLine( wxEmptyString );
  OutputDumpLine( wxEmptyString );
  return true;
  #else
  return false;
  #endif
}

#ifdef __WXDEBUG__
struct wxDebugStatsStruct {
  long instanceCount;
  long totalSize;
  wxChar *instanceClass;
  wxDebugStatsStruct *next;
};

static wxDebugStatsStruct *FindStatsStruct( wxDebugStatsStruct *st, wxChar *name ) {
  while( st ) {
    if( wxStrcmp( st->instanceClass, name ) == 0 ) {
      return st;
    }
    st = st->next;
  }
  return NULL;
}

static wxDebugStatsStruct *InsertStatsStruct( wxDebugStatsStruct *head, wxDebugStatsStruct *st ) {
  st->next = head;
  return st;
}
#endif

bool wxDebugContext::PrintStatistics( bool detailed ) {
  #ifdef __WXDEBUG__
  {
    wxChar* appName = ( wxChar* ) wxT( "application" );
    wxString appNameStr;
    if( wxTheApp ) {
      appNameStr = wxTheApp->GetAppName();
      appName = WXSTRINGCAST appNameStr;
      OutputDumpLine( wxT( "----- Memory statistics of %s at %s -----" ), appName, WXSTRINGCAST wxNow() );
    } else
    { OutputDumpLine( wxT( "----- Memory statistics -----" ) ); }
  }
  bool currentMode = GetDebugMode();
  SetDebugMode( false );
  long noNonObjectNodes = 0;
  long noObjectNodes = 0;
  long totalSize = 0;
  wxDebugStatsStruct *list = NULL;
  wxMemStruct *from = ( checkPoint ? checkPoint->m_next : ( wxMemStruct* )NULL );
  if( !from ) {
    from = wxDebugContext::GetHead();
  }
  wxMemStruct *st;
  for( st = from; st != 0; st = st->m_next ) {
    void* data = st->GetActualData();
    if( detailed && ( data != ( void* ) wxLog::GetActiveTarget() ) ) {
      wxChar *className = ( wxChar* ) wxT( "nonobject" );
      if( st->m_isObject && st->GetActualData() ) {
        wxObject *obj = ( wxObject * )st->GetActualData();
        if( obj->GetClassInfo()->GetClassName() ) {
          className = ( wxChar* )obj->GetClassInfo()->GetClassName();
        }
      }
      wxDebugStatsStruct *stats = FindStatsStruct( list, className );
      if( !stats ) {
        stats = ( wxDebugStatsStruct * )malloc( sizeof( wxDebugStatsStruct ) );
        stats->instanceClass = className;
        stats->instanceCount = 0;
        stats->totalSize = 0;
        list = InsertStatsStruct( list, stats );
      }
      stats->instanceCount ++;
      stats->totalSize += st->RequestSize();
    }
    if( data != ( void* ) wxLog::GetActiveTarget() ) {
      totalSize += st->RequestSize();
      if( st->m_isObject ) {
        noObjectNodes ++;
      } else
      { noNonObjectNodes ++; }
    }
  }
  if( detailed ) {
    while( list ) {
      OutputDumpLine( wxT( "%ld objects of class %s, total size %ld" ),
                      list->instanceCount, list->instanceClass, list->totalSize );
      wxDebugStatsStruct *old = list;
      list = old->next;
      free( ( char * )old );
    }
    OutputDumpLine( wxEmptyString );
  }
  SetDebugMode( currentMode );
  OutputDumpLine( wxT( "Number of object items: %ld" ), noObjectNodes );
  OutputDumpLine( wxT( "Number of non-object items: %ld" ), noNonObjectNodes );
  OutputDumpLine( wxT( "Total allocated size: %ld" ), totalSize );
  OutputDumpLine( wxEmptyString );
  OutputDumpLine( wxEmptyString );
  return true;
  #else
  ( void )detailed;
  return false;
  #endif
}

bool wxDebugContext::PrintClasses( void ) {
  {
    wxChar* appName = ( wxChar* ) wxT( "application" );
    wxString appNameStr;
    if( wxTheApp ) {
      appNameStr = wxTheApp->GetAppName();
      appName = WXSTRINGCAST appNameStr;
      wxLogMessage( wxT( "----- Classes in %s -----" ), appName );
    }
  }
  int n = 0;
  wxHashTable::compatibility_iterator node;
  wxClassInfo *info;
  wxClassInfo::sm_classTable->BeginFind();
  node = wxClassInfo::sm_classTable->Next();
  while( node ) {
    info = ( wxClassInfo * )node->GetData();
    if( info->GetClassName() ) {
      wxString msg( info->GetClassName() );
      msg += wxT( " " );
      if( info->GetBaseClassName1() && !info->GetBaseClassName2() ) {
        msg += wxT( "is a " );
        msg += info->GetBaseClassName1();
      } else if( info->GetBaseClassName1() && info->GetBaseClassName2() ) {
        msg += wxT( "is a " );
        msg += info->GetBaseClassName1() ;
        msg += wxT( ", " );
        msg += info->GetBaseClassName2() ;
      }
      if( info->GetConstructor() ) {
        msg += wxT( ": dynamic" );
      }
      wxLogMessage( msg );
    }
    node = wxClassInfo::sm_classTable->Next();
    n ++;
  }
  wxLogMessage( wxEmptyString );
  wxLogMessage( wxT( "There are %d classes derived from wxObject." ), n );
  wxLogMessage( wxEmptyString );
  wxLogMessage( wxEmptyString );
  return true;
}

void wxDebugContext::SetCheckpoint( bool all ) {
  if( all ) {
    checkPoint = NULL;
  } else
  { checkPoint = m_tail; }
}

int wxDebugContext::Check( bool checkAll ) {
  int nFailures = 0;
  wxMemStruct *from = ( checkPoint ? checkPoint->m_next : ( wxMemStruct* )NULL );
  if( !from || checkAll ) {
    from = wxDebugContext::GetHead();
  }
  for( wxMemStruct * st = from; st != 0; st = st->m_next ) {
    if( st->AssertIt() ) {
      nFailures += st->CheckBlock();
    } else
    { return -1; }
  }
  return nFailures;
}

int wxDebugContext::CountObjectsLeft( bool sinceCheckpoint ) {
  int n = 0;
  wxMemStruct *from = NULL;
  if( sinceCheckpoint && checkPoint ) {
    from = checkPoint->m_next;
  } else
  { from = wxDebugContext::GetHead() ; }
  for( wxMemStruct * st = from; st != 0; st = st->m_next ) {
    void* data = st->GetActualData();
    if( data != ( void* ) wxLog::GetActiveTarget() ) {
      n ++;
    }
  }
  return n ;
}

void wxDebugContext::OutputDumpLine( const wxChar *szFormat, ... ) {
  wxChar buf[2048];
  int count;
  va_list argptr;
  va_start( argptr, szFormat );
  buf[sizeof( buf ) / sizeof( wxChar ) - 1] = _T( '\0' );
  count = wxVsnprintf( buf, sizeof( buf ) / sizeof( wxChar ) - 3, szFormat, argptr );
  if( count < 0 ) {
    count = sizeof( buf ) / sizeof( wxChar ) - 3;
  }
  buf[count] = _T( '\r' );
  buf[count + 1] = _T( '\n' );
  buf[count + 2] = _T( '\0' );
  wxMessageOutputDebug dbgout;
  dbgout.Printf( buf );
}


#if USE_THREADSAFE_MEMORY_ALLOCATION
static bool memSectionOk = false;

class MemoryCriticalSection : public wxCriticalSection {
  public:
    MemoryCriticalSection() {
      memSectionOk = true;
    }
    ~MemoryCriticalSection() {
      memSectionOk = false;
    }
};

class MemoryCriticalSectionLocker {
  public:
    inline MemoryCriticalSectionLocker( wxCriticalSection& critsect )
      : m_critsect( critsect ), m_locked( memSectionOk ) { if( m_locked ) m_critsect.Enter(); }
    inline ~MemoryCriticalSectionLocker() { if( m_locked ) m_critsect.Leave(); }
  private:
    MemoryCriticalSectionLocker( const MemoryCriticalSectionLocker& );
    MemoryCriticalSectionLocker& operator=( const MemoryCriticalSectionLocker& );

    wxCriticalSection& m_critsect;
    bool m_locked;
};

static MemoryCriticalSection memLocker;

#endif // USE_THREADSAFE_MEMORY_ALLOCATION


#ifdef __WXDEBUG__
#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
#if wxUSE_GLOBAL_MEMORY_OPERATORS
void * operator new( size_t size, wxChar * fileName, int lineNum ) {
  return wxDebugAlloc( size, fileName, lineNum, false, false );
}

void * operator new( size_t size ) {
  return wxDebugAlloc( size, NULL, 0, false );
}

void operator delete( void * buf ) {
  wxDebugFree( buf, false );
}

#if wxUSE_ARRAY_MEMORY_OPERATORS
void * operator new[]( size_t size ) {
  return wxDebugAlloc( size, NULL, 0, false, true );
}

void * operator new[]( size_t size, wxChar * fileName, int lineNum ) {
  return wxDebugAlloc( size, fileName, lineNum, false, true );
}

void operator delete[]( void * buf ) {
  wxDebugFree( buf, true );
}
#endif // wxUSE_ARRAY_MEMORY_OPERATORS
#endif // wxUSE_GLOBAL_MEMORY_OPERATORS
#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))

void * wxDebugAlloc( size_t size, wxChar * fileName, int lineNum, bool isObject, bool ( isVect ) ) {
  #if USE_THREADSAFE_MEMORY_ALLOCATION
  MemoryCriticalSectionLocker lock( memLocker );
  #endif
  #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
  return ( void * )malloc( size );
  #endif
  if( !wxDebugContext::GetDebugMode() ) {
    return ( void * )malloc( size );
  }
  int totSize = wxDebugContext::TotSize( size );
  char * buf = ( char * ) malloc( totSize );
  if( !buf ) {
    wxLogMessage( wxT( "Call to malloc (%ld) failed." ), ( long )size );
    return 0;
  }
  wxMemStruct * st = ( wxMemStruct * )buf;
  st->m_firstMarker = MemStartCheck;
  st->m_reqSize = size;
  st->m_fileName = fileName;
  st->m_lineNum = lineNum;
  st->m_id = MemStructId;
  st->m_prev = 0;
  st->m_next = 0;
  st->m_isObject = isObject;
  if( st->Append() == 0 ) {
    st->ErrorMsg( "Trying to append new node" );
  }
  if( wxDebugContext::GetCheckPrevious() ) {
    if( st->CheckAllPrevious() < 0 ) {
      st->ErrorMsg( "Checking previous nodes" );
    }
  }
  char * ptr = wxDebugContext::MidMarkerPos( buf );
  * ( wxMarkerType * ) ptr = MemMidCheck;
  ptr = wxDebugContext::EndMarkerPos( buf, size );
  * ( wxMarkerType * ) ptr = MemEndCheck;
  void *m_actualData = ( void * ) wxDebugContext::CallerMemPos( buf );
  st->m_actualData = m_actualData;
  return m_actualData;
}

void wxDebugFree( void * buf, bool ( isVect ) ) {
  #if USE_THREADSAFE_MEMORY_ALLOCATION
  MemoryCriticalSectionLocker lock( memLocker );
  #endif
  if( !buf ) {
    return;
  }
  #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
  // VA 3.0 still has trouble in here
  free( ( char * )buf );
  #endif
  if( !wxDebugContext::GetDebugMode() ) {
    free( ( char * )buf );
    return;
  }
  char * startPointer = wxDebugContext::StartPos( ( char * ) buf );
  wxMemStruct * st = ( wxMemStruct * ) wxDebugContext::StructPos( startPointer );
  if( ! st->ValidateNode() ) {
    return;
  }
  if( st == wxDebugContext::checkPoint ) {
    wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
  }
  if( ! st->Unlink() ) {
    st->ErrorMsg( "Unlinking deleted node" );
  }
  st->SetDeleted();
  ( void ) memset( wxDebugContext::CallerMemPos( startPointer ), MemFillChar,
                   st->RequestSize() );
  free( ( char * )st );
}

#endif // __WXDEBUG__

void wxTrace( const wxChar * ... ) {
  wxFAIL_MSG( wxT( "wxTrace is now obsolete. Please use wxDebugXXX instead." ) );
}

void wxTraceLevel( int, const wxChar * ... ) {
  wxFAIL_MSG( wxT( "wxTrace is now obsolete. Please use wxDebugXXX instead." ) );
}

int wxDebugContextDumpDelayCounter::sm_count;

void wxDebugContextDumpDelayCounter::DoDump() {
  if( wxDebugContext::CountObjectsLeft( true ) > 0 ) {
    wxDebugContext::OutputDumpLine( wxT( "There were memory leaks.\n" ) );
    wxDebugContext::Dump();
    wxDebugContext::PrintStatistics();
  }
}

static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One;

#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
